using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;

namespace mebc.tests.boards
{
    [TestFixture]
    public class test_Board
    {
        [Test]
        public void Redirect_input()
        {
            var ci = new Input_only.CaptureInput();
            var sut = new Input_only(ci);

            sut.InputPipe(new Message<string> {Value = "hello"});

            Assert.AreEqual("hello", ci.received);
        }

        [Test]
        public void Capture_output()
        {
            var po = new Output_only.ProduceOutput();
            var sut = new Output_only(po);
            string result = null;
            sut.OutputPipe += _ => result = (string) _.Value;

            po.Run("hello");

            Assert.AreEqual("hello", result);
        }

        [Test]
        public void Wire_up_functional_units()
        {
            var sut = new Wiring_board();

            Assert.AreEqual("HELLOX", sut.Transform("hello"));
        }
    }


    class Input_only : Board
    {
        public class CaptureInput : Part
        {
            public string received;

            public CaptureInput()
            {
                Process<string>(_ => received = _);
            }
        }


        public Input_only(CaptureInput fu)
        {
            RedirectInputTo<string>(fu);
        }
    }


    class Output_only : Board
    {
        public class ProduceOutput : Part
        {
            public void Run(string t)
            {
                Send(t);
            }
        }

        public Output_only(ProduceOutput po)
        {
            CaptureOutputFrom<string>(po);
        }
    }


    class Wiring_board : Board
    {
        public Wiring_board()
        {
            var toUpper = new FuncPart<string, string>(t => t.ToUpper());
            var appendX = new FuncPart<string, string>(t => t + "X");

            RedirectInputTo<string>(toUpper);

            WireFromTo<string>(toUpper, appendX);

            CaptureOutputFrom<string>(appendX);
        }

        public string Transform(string t)
        {
            var result = "";
            Action<IMessage> catchOutput = _ => result = (string)_.Value;
            this.OutputPipe += catchOutput;

            this.InputPipe(new Message<string> {Value = t});

            return result;
        }
    }
}